/*
 * image.cpp
 *
 *  Created on: 18 oct. 2011
 *      Author: arthur
 */

#include "image.h"

Image::Image()
{
	this->estGris = false;
	this->motClef = "";
	this->nom = "";
	this->chemin = "";
	this->histogram = (float **) malloc(4 * sizeof(float *));
	int i;
	for (i = 0; i < 4; i++)
	{
		this ->histogram[i] = (float *) malloc(256 * sizeof(float));
	}
}

Image::~Image()
{
}

void Image::calculHistogram()
{
	int i, j;
	unsigned int nbPixelTotal = this->qImage.width() * this->qImage.height();

	if (this->estGris)
	{
		unsigned int histoTemp[256];
		for (j = 0; j < 256; j++)
		{
			histoTemp[j] = 0;
		}

		for (i = 0; i < this->qImage.width(); i++)
		{
			for (j = 0; j < this->qImage.height(); j++)
			{
				histoTemp[this->qImage.pixel(i, j) % 256]++;
			}
		}

		for (i = 0; i < 256; i++)
		{
			this->histogram[gris][i] = (float) histoTemp[i] / (float) nbPixelTotal * 100.;
		}

	}
	else
	{
		unsigned int histoTemp[4][256];

		for (j = 0; j < 256; j++)
		{
			histoTemp[rouge][j] = 0;
			histoTemp[vert][j] = 0;
			histoTemp[bleu][j] = 0;
			histoTemp[gris][j] = 0;
		}

		for (i = 0; i < this->qImage.width(); i++)
		{
			for (j = 0; j < this->qImage.height(); j++)
			{
				histoTemp[rouge][qRed(this->qImage.pixel(i, j))]++;
				histoTemp[vert][qGreen(this->qImage.pixel(i, j))]++;
				histoTemp[bleu][qBlue(this->qImage.pixel(i, j))]++;
				histoTemp[gris][qGray(this->qImage.pixel(i, j))]++;
			}
		}

		for (i = 0; i < 256; i++)
		{
			this->histogram[rouge][i] = (float) histoTemp[rouge][i] / (float) nbPixelTotal * 100.;
			this->histogram[vert][i] = (float) histoTemp[vert][i] / (float) nbPixelTotal * 100.;
			this->histogram[bleu][i] = (float) histoTemp[bleu][i] / (float) nbPixelTotal * 100.;
			this->histogram[gris][i] = (float) histoTemp[gris][i] / (float) nbPixelTotal * 100.;
		}
	}
}

float Image::distanceEuclidienne(float ** a, enum couleurHisto couleur, unsigned int intervalMin,
		unsigned int intervalMax)
{
	unsigned int i;
	float distanceEuclidienne = 0., temp;

	for (i = intervalMin; i <= intervalMax; i++)
	{
		temp = a[couleur][i] - this->histogram[couleur][i];
		distanceEuclidienne += temp < 0. ? -temp : temp;
	}
	distanceEuclidienne = (float) (distanceEuclidienne / (intervalMax - intervalMin + 1));

	return distanceEuclidienne;
}

bool Image::getEstGris() const
{
	return estGris;
}

float **Image::getHistogram() const
{
	return histogram;
}

QImage Image::getImage() const
{
	return qImage;
}

string Image::getNom() const
{
	return nom;
}

void Image::setEstGris(bool estGris)
{
	this->estGris = estGris;
}

void Image::setHistogram(float **histogram)
{
	this->histogram = histogram;
}

void Image::setImage(QImage qImage)
{
	this->qImage = qImage;
}

void Image::setNom(string nom)
{
	this->nom = nom;
}

void Image::convertirEnNiveauDeGris()
{
	int i, j, grisTemp;
	for (i = 0; i < this->qImage.width(); i++)
	{
		for (j = 0; j < this->qImage.height(); j++)
		{
			grisTemp = qGray(this->qImage.pixel(i, j));
			this->qImage.setPixel(i, j, qRgb(grisTemp, grisTemp, grisTemp));
		}
	}
	this->estGris = true;
}

Image::couleurHisto Image::couleurDominante()
{
	if (!this->estGris)
	{
		float r = 0.0, v = 0.0, b = 0.0;
		int i;
		for (i = 0; i < 256; i++)
		{
			r += this->histogram[Image::rouge][i] * i;
			b += this->histogram[Image::bleu][i] * i;
			v += this->histogram[Image::vert][i] * i;
		}
		if (r > ((b + v) * 0.75))
		{
			return Image::rouge;
		}
		else if (b > (v + r) * 0.75)
		{
			return Image::bleu;
		}
		else if (v > (r + b) * 0.75)
		{
			return Image::vert;
		}
		else
		{
			return Image::gris;
		}
	}
	else
	{
		return Image::gris;
	}
}

Image::luminosite Image::luminositeDominante()
{
	float cl = 0.0, med = 0.0, so = 0.0;
	int i;
	for (i = 0; i < 85; i++)
	{
		cl += this->histogram[Image::gris][i + 170] * (i);
		so += this->histogram[Image::gris][i] * (85 - i);
		med += this->histogram[Image::gris][i + 85] * 42.5;
	}
	if (cl > (so + med) * 0.75)
	{
		return Image::clair;
	}
	else if (so > (med + cl) * 0.75)
	{
		return Image::sombre;
	}
	else
	{
		return Image::median;
	}
}

QList<QList<Image> > Image::classementImage(QList<Image> imageAClasser)
{
	QList<QList<Image> > imageClasse = *new QList<QList<Image> > ();

	//Classement par categorie

	int i;
	for (i = 0; i < 5; i++)
	{
		imageClasse.append(*new QList<Image> ());
	}

	for (i = 0; i < imageAClasser.size(); i++)
	{
		switch (imageAClasser[i].couleurDominante())
		{
			case Image::rouge:
			{
				imageClasse[Image::rouge].append(imageAClasser[i]);
				break;
			}
			case Image::vert:
			{
				imageClasse[Image::vert].append(imageAClasser[i]);
				break;
			}
			case Image::bleu:
			{
				imageClasse[Image::bleu].append(imageAClasser[i]);
				break;
			}
		}
		switch (imageAClasser[i].luminositeDominante())
		{
			case Image::clair:
			{
				imageClasse[Image::clair - 7].append(imageAClasser[i]);
				break;
			}
			case Image::sombre:
			{
				imageClasse[Image::sombre - 7].append(imageAClasser[i]);
				break;
			}
		}
	}

	//Mis en avant de l'image la plus significative (première position)

	float ** histoMoyen = histogramesMoyen(imageClasse[Image::rouge]);
	float meilleurDistanceEuclidienne = 0.0, distanceEuclidienneImageCourante = 0.0;
	for (i = 0; i < imageClasse[Image::rouge].size(); i++)
	{
		if (i == 0)
		{
			meilleurDistanceEuclidienne = imageClasse[Image::rouge][0].distanceEuclidienne(
					histoMoyen, Image::rouge, 0, 255);
		}
		else
		{
			distanceEuclidienneImageCourante = imageClasse[Image::rouge][i].distanceEuclidienne(
					histoMoyen, Image::rouge, 0, 255);
			if (distanceEuclidienneImageCourante < meilleurDistanceEuclidienne)
			{
				imageClasse[Image::rouge].move(i, 0);
				meilleurDistanceEuclidienne = distanceEuclidienneImageCourante;
			}

		}
	}

	histoMoyen = histogramesMoyen(imageClasse[Image::bleu]);
	for (i = 0; i < imageClasse[Image::bleu].size(); i++)
	{
		if (i == 0)
		{
			meilleurDistanceEuclidienne = imageClasse[Image::bleu][0].distanceEuclidienne(
					histoMoyen, Image::bleu, 0, 255);
		}
		else
		{
			distanceEuclidienneImageCourante = imageClasse[Image::bleu][i].distanceEuclidienne(
					histoMoyen, Image::bleu, 0, 255);
			if (distanceEuclidienneImageCourante < meilleurDistanceEuclidienne)
			{
				imageClasse[Image::bleu].move(i, 0);
				meilleurDistanceEuclidienne = distanceEuclidienneImageCourante;
			}

		}
	}

	histoMoyen = histogramesMoyen(imageClasse[Image::vert]);
	for (i = 0; i < imageClasse[Image::vert].size(); i++)
	{
		if (i == 0)
		{
			meilleurDistanceEuclidienne = imageClasse[Image::vert][0].distanceEuclidienne(
					histoMoyen, Image::vert, 0, 255);
		}
		else
		{
			distanceEuclidienneImageCourante = imageClasse[Image::vert][i].distanceEuclidienne(
					histoMoyen, Image::vert, 0, 255);
			if (distanceEuclidienneImageCourante < meilleurDistanceEuclidienne)
			{
				imageClasse[Image::vert].move(i, 0);
				meilleurDistanceEuclidienne = distanceEuclidienneImageCourante;
			}

		}
	}

	histoMoyen = histogramesMoyen(imageClasse[Image::clair - 7]);
	for (i = 0; i < imageClasse[Image::clair - 7].size(); i++)
	{
		if (i == 0)
		{
			meilleurDistanceEuclidienne = imageClasse[Image::clair - 7][0].distanceEuclidienne(
					histoMoyen, Image::gris, 170, 255);
		}
		else
		{
			distanceEuclidienneImageCourante
					= imageClasse[Image::clair - 7][i].distanceEuclidienne(histoMoyen, Image::gris,
							170, 255);
			if (distanceEuclidienneImageCourante < meilleurDistanceEuclidienne)
			{
				imageClasse[Image::clair - 7].move(i, 0);
				meilleurDistanceEuclidienne = distanceEuclidienneImageCourante;
			}

		}
	}

	histoMoyen = histogramesMoyen(imageClasse[Image::sombre - 7]);
	for (i = 0; i < imageClasse[Image::sombre - 7].size(); i++)
	{
		if (i == 0)
		{
			meilleurDistanceEuclidienne = imageClasse[Image::sombre - 7][0].distanceEuclidienne(
					histoMoyen, Image::gris, 0, 85);
		}
		else
		{
			distanceEuclidienneImageCourante
					= imageClasse[Image::sombre - 7][i].distanceEuclidienne(histoMoyen,
							Image::gris, 0, 85);
			if (distanceEuclidienneImageCourante < meilleurDistanceEuclidienne)
			{
				imageClasse[Image::sombre - 7].move(i, 0);
				meilleurDistanceEuclidienne = distanceEuclidienneImageCourante;
			}

		}
	}

	return imageClasse;
}

float **Image::histogramesMoyen(QList<Image> imageAMoyenner)
{
	float ** histoMoyen = (float **) malloc(4 * sizeof(float *));

	int i, j, nbImages = imageAMoyenner.size();

	for (i = 0; i < 4; i++)
	{
		histoMoyen[i] = (float *) malloc(256 * sizeof(float));
	}

	for (i = 0; i < nbImages; i++)
	{
		for (j = 0; j < 256; j++)
		{
			if (i == 0)
			{
				histoMoyen[Image::rouge][j] = 0.0;
				histoMoyen[Image::vert][j] = 0.0;
				histoMoyen[Image::bleu][j] = 0.0;
				histoMoyen[Image::gris][j] = 0.0;
			}
			histoMoyen[Image::rouge][j] += imageAMoyenner[i].histogram[Image::rouge][j] / nbImages;
			histoMoyen[Image::vert][j] += imageAMoyenner[i].histogram[Image::vert][j] / nbImages;
			histoMoyen[Image::bleu][j] += imageAMoyenner[i].histogram[Image::bleu][j] / nbImages;
			histoMoyen[Image::gris][j] += imageAMoyenner[i].histogram[Image::gris][j] / nbImages;
		}
	}

	return histoMoyen;
}

unsigned int distanceEuclidienneHistogrammes(Image image1, Image image2)
{
	return (unsigned int) (image1.distanceEuclidienne(image2.histogram, Image::gris, 0, 255)
			* 127.5);
}

